본문으로 건너뛰기

23.07.22

오늘 한 일

  • Gloddy 개발

Gloddy 개발 - useFunnel 타입 추론

useFunnel을 직접 구현하면서 타입 추론이 잘 안되는 문제가 있었다.

const { Funnel, prevStep, nextStep } = useFunnel(['praise', 'mate']);

return (
<Funnel>
<Funnel.Step name="이상한스텝으로적어도에러안뜸">
<PraiseComponent onPrevClick={prevStep} onNextClick={nextStep} />
</Funnel.Step>
<Funnel.Step name="mate">
<MateComponent onPrevClick={prevStep} onNextClick={nextStep} />
</Funnel.Step>
</Funnel>
);

이 부분은 내부적으로 에러를 던져서 막아주긴 했는데, 더 나아가서 리터럴 타입으로 추론이 되도록 하고 싶었다.

토스의 useFunnel은 어떻게 했을까?

토스의 useFunnelas const로 타입 단언해서 리터럴 타입으로 추론이 가능하게 했다.

image

타입 단언 안하면 추론 못한다는 것이다. 나는 내부적으로 처리해서 타입 단언을 안해도 되도록 만들고 싶었다.

내 방식

useFunnel의 파라미터로 넘겨주는 stepsreadonly 붙여서 리터럴 타입으로 만들었다.

export function useFunnel<Steps extends NonEmptyArray<string>>(
steps: readonly [...Steps],
options?: { initialStep?: Steps[number]; stepQueryKey?: string }
) {
//...
}

이제 useFunnel에서 타입 단언하지 않아도 리터럴 타입으로 추론이 가능하다..!!

[...Steps]로 한 이유

readonly Steps로 하면 다음과 같은 에러메시지가 뜬다.

'readonly' type modifier is only permitted on array and tuple literal types.

readonly는 배열과 튜플 리터럴 타입에만 허용된다고 한다. Steps는 그냥 type이기 때문에 readonly를 붙일 수 없다.

해결법은 두 가지다.

  • readonly [...Steps] : 튜플 리터럴 타입으로 변환
  • Readonly<Steps> : Readonly 타입으로 변환
type Readonly<T> = {
readonly [P in keyof T]: T[P];
};

Readonly는 제네릭 T의 모든 프로퍼티를 readonly로 변환하는 타입이다.

Gloddy 개발 - react-hook-form 에러 해결

어제 잘 안됐던 문제를 해결했다.

일단 저 에러는 Deepl 번역 크롬 확장 프로그램의 문제였다.. 그냥 지워버리니 해결됐다.

근데 다른 문제가 있었다. textarea에 입력을 하면 focus가 사라진다.

이 문제는 부모 컴포넌트에서 react-hook-formhandleSubmit까지 자식 컴포넌트로 넘겨주면서 발생했다.

// 부모 컴포넌트
export default function FeedbackWrapper() {
const { Funnel, prevStep, nextStep } = useFunnel(['praise', 'mate']);
const { handleSubmit, control } = useFeedbackContext();

const onSubmit = (data: FeedbackRequestType) => {
console.log(data);
};

return (
<Funnel>
<Funnel.Step name="praise">
<PraiseComponent onPrevClick={prevStep} onNextClick={nextStep} />
</Funnel.Step>
<Funnel.Step name="mate">
<MateComponent
onPrevClick={prevStep}
onNextClick={handleSubmit(onSubmit)} // 이 부분
control={control}
/>
</Funnel.Step>
</Funnel>
);

부모에게서 넘겨받은 handleSubmit(onSubmit)과 내부적으로 사용하는 useFeedbackContext가 겹쳐져서 렌더링 이슈가 발생한 것 같다.

그래서 자식 컴포넌트 쪽에서 이렇게 처리했다.

// 자식 컴포넌트
export default function MateComponent({ onPrevClick, onNextClick }: MateComponentProps) {
const {
handleSubmit,
formState: { isDirty, isValid },
} = useFeedbackContext();

return (
<main>
<TopNavigationBar
text="최고의 짝꿍"
leftNode={
<Image
src="/assets/arrow_back.svg"
width={8}
height={30}
alt="back"
onClick={onPrevClick}
className="cursor-pointer"
/>
}
/>
<MateCardList userList={DUMMY_USERLIST} />
<Spacing size={100} />
<BottomFixedButton
text="완료"
onClick={handleSubmit(onNextClick!)}
disabled={!isDirty || !isValid}
/>
</main>
);
}

onNextClickhandleSubmit으로 감싸서 넘겨주어서 해결했다.


내일 할 일

  • 휴식